import random
from django import forms
from django.conf import settings
# from app01 import models
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
from web import models
from utils.tencent.sms import send_sms_single
from django_redis import get_redis_connection
from utils import encrypt

from redis import *

from web.forms.bootstrap import BootStrapForm


class RegisterModelformPost(BootStrapForm, forms.ModelForm):
    """ 注册的 """
    password = forms.CharField(label='密码',
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': '密码长度不能小于8个字符',
                                   'max_length': '密码长度不能大于64个字符'
                               },
                               widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'}))
    # django会检测数据库中有没有字段，有则覆盖，没有就添加
    confirm_password = forms.CharField(
        label='确认密码',
        min_length=8,
        max_length=64,
        error_messages={
            'min_length': '重复密码长度不能小于8个字符',
            'max_length': '重复密码长度不能大于64个字符'
        },
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': '请输入确认密码'
        }), )
    # RegexValidator 添加re正则
    # mobile_phone = forms.CharField(label='手机号', validators=[
    #     RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'), '手机号格式错误'
    # ])

    code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入验证码'}))

    class Meta:
        model = models.UserInfo
        fields = "__all__"  # 默认显示
        # fields = [
        #     'username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code'
        # ]

    def clean_username(self):
        """ 校验用户名不能重复 """
        username = self.cleaned_data['username']
        exists = models.UserInfo.objects.filter(username=username).exists()
        if exists:
            raise ValidationError('用户名已存在')
        return username

    def clean_email(self):
        """ 校验邮箱是否存在 """
        email = self.cleaned_data['email']
        exists = models.UserInfo.objects.filter(email=email).exists()
        if exists:
            raise ValidationError('邮箱已注册')
        return email

    def clean_password(self):
        """ 密码加密 """
        pwd = self.cleaned_data['password']
        # 加密并返回
        return encrypt.md5(pwd)

    def clean_confirm_password(self):
        """ 校验密码是否一致 """
        pwd = self.cleaned_data.get('password')
        confirm_pwd = encrypt.md5(self.cleaned_data['confirm_password'])
        if pwd != confirm_pwd:
            raise ValidationError('确认密码和密码不一致')
        return confirm_pwd

    def clean_mobile_phone(self):
        """ 校验手机号是否注册 """
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if exists:
            raise ValidationError('手机号已注册')
        return mobile_phone

    # def clean_code(self):
    #     """ 校验验证码是否正确 """
    #     code = self.cleaned_data['code']  # 验证码
    #     # mobile_phone = self.cleaned_data['mobile_phone']  # 手机号
    #     mobile_phone = self.cleaned_data.get('mobile_phone')  # 手机号
    #     if not mobile_phone:
    #         return code
    #
    #     # conn = get_redis_connection()
    #     redis_code = conn.get(mobile_phone)
    #     if not redis_code:
    #         raise ValidationError('验证码未发送或过期，请从新发送')
    #
    #     # redis_code 是字节
    #     redis_str_code = redis_code.decode('utf-8')
    #     # print(code, '11111111')
    #     # print(redis_code)
    #     # print(redis_code.decode('utf-8'), '22222222')
    #     # print(redis_str_code, '33333333')
    #     # if code.strip() != redis_str_code.strip():
    #     if code.strip() != redis_str_code:
    #         raise ValidationError('验证码错误，请重新输入')
    #
    #     return code


class RegisterModelform(BootStrapForm, forms.ModelForm):
    """ 页面 """
    # username = forms.CharField(label='用户名', )

    # widget 修改输入类
    password = forms.CharField(label='密码',
                               min_length=8,
                               max_length=64,
                               error_messages={
                                   'min_length': '密码长度不能小于8个字符',
                                   'max_length': '密码长度不能大于64个字符'
                               },
                               widget=forms.PasswordInput(attrs={'class': 'form-control', 'placeholder': '请输入密码'}))
    # django会检测数据库中有没有字段，有则覆盖，没有就添加
    confirm_password = forms.CharField(
        label='确认密码',
        min_length=8,
        max_length=64,
        error_messages={
            'min_length': '重复密码长度不能小于8个字符',
            'max_length': '重复密码长度不能大于64个字符'
        },
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': '请输入确认密码'
        }), )
    # RegexValidator 添加re正则
    mobile_phone = forms.CharField(label='手机号', validators=[
        RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'), '手机号格式错误'
    ])

    code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入验证码'}))

    class Meta:
        model = models.UserInfo
        # fields = "__all__"    # 默认显示
        fields = [
            'username', 'email', 'password', 'confirm_password', 'mobile_phone', 'code'
        ]

    # 重写父类init方法 [ 继承了
    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     for name, field in self.fields.items():
    #         field.widget.attrs['class'] = 'form-control'
    #         field.widget.attrs['placeholder'] = f'请输入{field.label}'


# 连接redis数据库
conn = Redis(host='192.168.137.214', port=6379, password='205714wp.', encoding='utf-8')


class SendSmsForm(forms.Form):
    """ 发送短信 """
    mobile_phone = forms.CharField(label='手机号', validators=[RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$', '手机号格式错误'), ])

    # 重写init方法得到其他视图中的参数
    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_mobile_phone(self):
        """ 手机号校验的钩子 """
        # 获取
        mobile_phone = self.cleaned_data['mobile_phone']

        # 判断短信模板是否正确
        # tpl = self.request.GET.get('tpl')
        # tpl = self.cleaned_data['tpl']

        tpl = self.request.GET.get('tpl')
        # tpl = self.data.get('tpl')
        template_id = settings.TENCENT_SMS_TEMPLATE.get(tpl)
        # print(tpl)
        # print(template_id)
        if not template_id:
            raise ValidationError('模板错误')

        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if tpl == 'login':
            if not exists:
                # 自动抛出异常
                raise ValidationError('手机号未注册,请先注册')
        else:
            # 校验数据库中是否已有手机号
            # exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
            if exists:
                # 自动抛出异常
                raise ValidationError('手机号已注册')

        # 发短信 & 写到redis
        code = random.randrange(1000, 9999)  # 生成的随机数字
        # 发短信
        print(f'验证码：{code}')
        sms = send_sms_single(mobile_phone, template_id, [code, ])
        if sms['result'] != 0:
            raise ValidationError(f'短信发送失败, {sms["errmsg"]}')

        # 验证码写入redis中（django-redis）
        # conn = get_redis_connection()

        # Invalid input of type: 'Redis'. Convert to a bytes, string, int or float first.
        # 降低radis版本
        conn.set(mobile_phone, conn, ex=60)

        return mobile_phone

    def clean_code(self):
        """ 校验验证码是否正确 """
        code = self.cleaned_data['code']  # 验证码
        # mobile_phone = self.cleaned_data['mobile_phone']  # 手机号
        mobile_phone = self.cleaned_data.get('mobile_phone')  # 手机号
        if not mobile_phone:
            return code

        # conn = get_redis_connection()
        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码未发送或过期，请从新发送')

        # redis_code 是字节
        redis_str_code = redis_code.decode('utf-8')
        # print(code, '11111111')
        # print(redis_code)
        # print(redis_code.decode('utf-8'), '22222222')
        # print(redis_str_code, '33333333')
        # if code.strip() != redis_str_code.strip():
        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误，请重新输入')

        return code


class LoginSmsForm(BootStrapForm, forms.Form):
    """ 验证码登录 """
    mobile_phone = forms.CharField(label='手机号', validators=[
        RegexValidator(r'^(1[3|4|5|6|7|8|9])\d{9}$'), '手机号格式错误'
    ])

    code = forms.CharField(label='验证码', widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': '请输入验证码'}))

    # 想要给form加样式，重写父类__init__方法
    # 继承了BootStrapForm 这个类
    # def __init__(self, *args, **kwargs):
    #     super().__init__(*args, **kwargs)
    #     for name, field in self.fields.items():
    #         field.widget.attrs['class'] = 'form-control'
    #         field.widget.attrs['placeholder'] = f'请输入{field.label}'

    # def clean_mobile_phone(self):
    #     mobile_phone = self.cleaned_data['mobile_phone']
    #     exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
    #     if not exists:
    #         raise ValidationError('手机号未注册')
    #     # 如果用户手机号已经注册 返回
    #     return mobile_phone
    #
    # def clean_code(self):
    #     mobile_phone = self.cleaned_data.get('mobile_phone')
    #     code = self.cleaned_data['code']
    #     # 手机号不存在，则验证码无需再校验
    #     if not mobile_phone:
    #         return code
    #
    #     redis_code = conn.get(mobile_phone)
    #     if not redis_code:
    #         raise ValidationError('验证码未发送或过期，请从新发送')
    #
    #     # redis_code 是字节
    #     redis_str_code = redis_code.decode('utf-8')
    #     if code.strip() != redis_str_code:
    #         raise ValidationError('验证码错误，请重新输入')
    #     return code


class LoginSmsFormPost(BootStrapForm, forms.Form):
    """ 短信验证码登录 """

    def clean_mobile_phone(self):
        mobile_phone = self.cleaned_data['mobile_phone']
        exists = models.UserInfo.objects.filter(mobile_phone=mobile_phone).exists()
        if not exists:
            raise ValidationError('手机号未注册')
        # 如果用户手机号已经注册 返回
        return mobile_phone

    def clean_code(self):
        mobile_phone = self.cleaned_data.get('mobile_phone')
        code = self.cleaned_data['code']
        # 手机号不存在，则验证码无需再校验
        if not mobile_phone:
            return code

        redis_code = conn.get(mobile_phone)
        if not redis_code:
            raise ValidationError('验证码未发送或过期，请从新发送')

        # redis_code 是字节
        redis_str_code = redis_code.decode('utf-8')
        if code.strip() != redis_str_code:
            raise ValidationError('验证码错误，请重新输入')
        return code


class LoginForm(BootStrapForm, forms.Form):
    """ 账户密码登录 """
    username = forms.CharField(label='邮箱或手机号')
    password = forms.CharField(label='密码', widget=forms.PasswordInput(render_value=True))
    code = forms.CharField(label='图片验证码')

    def __init__(self, request, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.request = request

    def clean_password(self):
        pwd = self.cleaned_data['password']
        # 加密 & 返回
        return encrypt.md5(pwd)

    def clean_code(self):
        """ 钩子 图片验证码是否正确 """
        # 读取用户输入的验证码
        code = self.cleaned_data['code']
        # 获取生成验证码时保存的【session
        session_code = self.request.session.get('image_code')

        if not session_code:
            raise ValidationError('验证码已过期，请重新获取')

        if code.strip().upper() != session_code.strip().upper():
            raise ValidationError('验证码错误')

        return code
